package com.jiunuan.live.core.server.handler.impl;

import com.alibaba.fastjson2.JSON;
import com.jiunuan.live.common.interfaces.topic.ImCoreServerProviderTopicNames;
import com.jiunuan.live.core.server.common.ChannelHandlerContextCache;
import com.jiunuan.live.core.server.common.ImContextUtils;
import com.jiunuan.live.core.server.common.ImMsg;
import com.jiunuan.live.core.server.handler.SimplyHandler;
import com.jiunuan.live.framework.redis.starter.key.IMCoreServerProviderCacheKeyBuilder;
import com.jiunuan.live.im.constants.ImConstants;
import com.jiunuan.live.im.constants.ImMsgCodeEnum;
import com.jiunuan.live.im.core.server.interfaces.dto.ImOnlineDTO;
import com.jiunuan.live.im.dto.ImMsgBody;
import com.jiunuan.live.im.interfaces.ImTokenRpc;
import io.netty.channel.ChannelHandlerContext;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.MQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @Author: JiuNuan
 * @CreateTime: 2024-08-10 21:49
 * @Description: 登录消息包实现类,登录消息处理同一收拢到这一个类中
 */
@Slf4j
@Component
public class LoginMsgHandler implements SimplyHandler {
    @DubboReference
    private ImTokenRpc imTokenRpc;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IMCoreServerProviderCacheKeyBuilder cacheKeyBuilder;
    @Resource
    private MQProducer mqProducer;
    /**
     * 消息处理函数，根据code匹配不同实现类
     *
     * @param ctx
     * @param imMsg
     */
    @Override
    public void handler(ChannelHandlerContext ctx, ImMsg imMsg) {
        // 防止重复请求
        if(ImContextUtils.getUserId(ctx)!=null){
            return;
        }
        byte[] body = imMsg.getBody();
        if(body == null || body.length == 0){
            ctx.close();
            log.error("[LoginMsgHandler]消息体为空，imMsg:" + imMsg);
            throw new RuntimeException("消息体为空");
        }
        ImMsgBody imMsgBody = JSON.parseObject(new String(body),ImMsgBody.class);
        // 参数校验
        Long userIdFromMsg = imMsgBody.getUserId();
        Integer appId = imMsgBody.getAppId();
        String token = imMsgBody.getToken();

        if(StringUtils.isEmpty(token)|| userIdFromMsg < 10000 || appId < 10000){
            ctx.close();
            log.error("[LoginMsgHandler] param error,imMsg" + imMsg);
            throw new RuntimeException("param error");
        }
        // 新建模块用于token校验
        Long userId = imTokenRpc.getUserIdByToken(token);
        //token校验成功，而且和传递过来的userId是同一个，则允许建立连接
        if(userId != null && userId.equals(userIdFromMsg)){
            loginSuccessHandler(ctx, userId, appId, null);
            return;
        }
        ctx.close();
        log.error("[LoginMsgHandler]token check error,imMsg:"+ imMsg);
        throw new RuntimeException("[LoginMsgHandler] token check error");
    }

    /**
     * 发送登录消息到mq
     * @param userId
     * @param appId
     */
    private void sendLoginMQ(Long userId, Integer appId, Integer roomId) {
        ImOnlineDTO imOnlineDTO = new ImOnlineDTO();
        imOnlineDTO.setUserId(userId);
        imOnlineDTO.setAppId(appId);
        imOnlineDTO.setRoomId(roomId);
        imOnlineDTO.setLoginTime(System.currentTimeMillis());
        Message message = new Message();
        message.setTopic(ImCoreServerProviderTopicNames.IM_ONLINE_TOPIC);
        message.setBody(JSON.toJSONString(imOnlineDTO).getBytes());
        try {
            SendResult sendResult = mqProducer.send(message);
            log.info("[sendLoginMQ] sendResult is {}", sendResult);
        } catch (Exception e) {
            log.error("[sendLoginMQ] error is: ", e);
        }
    }

    /**
     * 如果用户成功登录，就处理相关记录
     */
    public void loginSuccessHandler(ChannelHandlerContext ctx, Long userId, Integer appId, Integer roomId) {
        //按照userId保存好相关的channel对象信息
        ChannelHandlerContextCache.put(userId, ctx);
        ImContextUtils.setUserId(ctx, userId);
        ImContextUtils.setAppId(ctx, appId);
        if (roomId != null) {
            ImContextUtils.setRoomId(ctx, roomId);
        }
        //将im消息回写给客户端
        ImMsgBody respBody = new ImMsgBody();
        respBody.setAppId(appId);
        respBody.setUserId(userId);
        respBody.setData("true");
        ImMsg respMsg = ImMsg.build(ImMsgCodeEnum.IM_LOGIN_MSG.getCode(),JSON.toJSONString(respBody));
        stringRedisTemplate.opsForValue().set(cacheKeyBuilder.buildIMBindIpKey(appId,userId),
                ChannelHandlerContextCache.getServerIpAddress() + "%" + userId,
                ImConstants.DEFAULT_HEART_BEAT_GAP * 2, TimeUnit.SECONDS);
        log.info("[LoginMsgHandler] login success,userId is {},appId is {}", userId, appId);
        ctx.writeAndFlush(respMsg);
        sendLoginMQ(userId, appId, roomId);
    }
}
